﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

// PMD文件解析，全局访问
// 这是一个内部数据结构，用于在整个应用程序中传递解析后的模型数据

// 需注意由于PMD历史遗留问题，可能会无法读取部分文件。
public class ModelData
{
    public string FilePath { get; set; }
    public string ModelName { get; set; } // 用于导出的首选名称
    public string ModelNameJp { get; set; }
    public string ModelNameEn { get; set; }
    public List<MorphData> Morphs { get; set; } = new List<MorphData>();
}

public class MorphData
{
    public int Id { get; set; }
    public string NameJp { get; set; }
    public string NameEn { get; set; }
}

/// <summary>
/// PMD文件解析器
/// C#实现参考了C++项目 'oguna/MMDFormats'。
/// https://github.com/oguna/MMDFormats
/// 注意：PMD文件的字符串编码是 Shift_JIS。
/// </summary>
public static class PmdParser
{
    // 获取Shift_JIS编码，这是解析PMD文件的关键
    private static readonly Encoding ShiftJisEncoding;

    static PmdParser()
    {
        Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); // 注册编码提供程序以支持Shift_JIS
        ShiftJisEncoding = Encoding.GetEncoding("Shift_JIS");
    }

    /// <summary>
    /// 从字节数组中读取一个固定长度、以null结尾的字符串
    /// </summary>
    private static string ReadFixedString(BinaryReader reader, int length)
    {
        byte[] bytes = reader.ReadBytes(length);
        string text = ShiftJisEncoding.GetString(bytes);
        int nullCharIndex = text.IndexOf('\0');
        return nullCharIndex >= 0 ? text.Substring(0, nullCharIndex) : text;
    }

    // 数据解析
    public static ModelData Parse(string filePath)
    {
        var modelData = new ModelData() { FilePath = filePath };

        using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
        using (BinaryReader br = new BinaryReader(fs, ShiftJisEncoding))
        {
            // --- 头部 ---
            if (new string(br.ReadChars(3)) != "Pmd") throw new Exception(LocalizationManager.GetString("Error_NotPmdFile")); // 不是有效的PMD文件。
            br.ReadSingle(); // Version
            modelData.ModelNameJp = ReadFixedString(br, 20);
            ReadFixedString(br, 256);// Comment

            // --- 跳过不需要的数据 ---
            uint vertexCount = br.ReadUInt32();
            br.BaseStream.Seek(vertexCount * 38, SeekOrigin.Current); // 跳过顶点数据
            uint indexCount = br.ReadUInt32();
            br.BaseStream.Seek(indexCount * 2, SeekOrigin.Current); // 跳过面数据
            uint materialCount = br.ReadUInt32();
            br.BaseStream.Seek(materialCount * 70, SeekOrigin.Current); // 跳过材质数据
            ushort boneCount = br.ReadUInt16();
            br.BaseStream.Seek(boneCount * 39, SeekOrigin.Current);  // 跳过骨骼数据
            ushort ikCount = br.ReadUInt16();
            for (int i = 0; i < ikCount; i++) { br.BaseStream.Seek(6, SeekOrigin.Current); byte chainLength = br.ReadByte(); br.BaseStream.Seek(chainLength * 2, SeekOrigin.Current); }

            // --- 读取表情(Morph)数据 ---
            ushort morphCount = br.ReadUInt16();
            for (int i = 0; i < morphCount; i++) // IK数据长度可变，需要循环跳过
            {
                var morph = new MorphData { Id = i, NameJp = ReadFixedString(br, 20) };
                uint morphVertexCount = br.ReadUInt32();
                br.BaseStream.Seek(1, SeekOrigin.Current);
                br.BaseStream.Seek(morphVertexCount * 16, SeekOrigin.Current);
                modelData.Morphs.Add(morph);
            }

            // --- 英文名部分 ---
            // 使用 try-catch 来安全地读取可选的英文数据块
            try
            {
                // 在尝试读取前，先做一个基本的检查，确保流中至少还有1个字节
                if (br.BaseStream.Position < br.BaseStream.Length)
                {
                    byte englishNameExist = br.ReadByte();
                    if (englishNameExist == 1)
                    {
                        modelData.ModelNameEn = ReadFixedString(br, 20);
                        ReadFixedString(br, 256);
                        br.BaseStream.Seek(boneCount * 20, SeekOrigin.Current);
                        // 即使标记存在，文件也可能在这里意外结束，所以每次读取都可能是危险的
                        for (int i = 0; i < morphCount; i++)
                        {
                            if (i < modelData.Morphs.Count) { modelData.Morphs[i].NameEn = ReadFixedString(br, 20); } else { br.BaseStream.Seek(20, SeekOrigin.Current); }
                        }
                    }
                }
            }
            catch (EndOfStreamException) { } // 当读取到文件末尾时，出发异常，忽略英文名部分。
        }
        // ============================================

        // 1. 设置首选名称
        modelData.ModelName = !string.IsNullOrWhiteSpace(modelData.ModelNameJp) ? modelData.ModelNameJp : modelData.ModelNameEn;

        // 2. 如果首选名称仍然为空，则使用文件名作为备用
        if (string.IsNullOrWhiteSpace(modelData.ModelName))
        {
            modelData.ModelName = Path.GetFileNameWithoutExtension(filePath);
        }

        return modelData;

    }
}